package com.springsummer.information.green.webmvc;


import com.springsummer.information.green.annotation.Controller;
import com.springsummer.information.green.beans.AnnotationConfigApplicationContext;
import com.springsummer.information.green.beans.ApplicationContext;
import com.springsummer.information.green.io.NormalScanService;
import com.springsummer.information.green.io.ScanService;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.logging.Logger;

public class DispatchServlet extends HttpServlet {

    private static Logger logger = Logger.getLogger(DispatchServlet.class.getName());

    private static final String SCAN_PACKAGE_NAME="com.springsummer.information.green.webmvc.controllers";


    private AnnotationConfigApplicationContext applicationContext;

    private RequestMappingHandlerMapping handlerMapping;

    private HandlerAdapter handlerAdapter;

    private ViewResolver viewResolver;

    @Override
    public void init(ServletConfig config) throws ServletException {
        logger.info("MyDispatchServlet init..."+new Date());
        super.init(config);
        this.applicationContext=new AnnotationConfigApplicationContext(SCAN_PACKAGE_NAME);
        this.initStrategies(this.applicationContext);
    }

    protected void initStrategies(ApplicationContext context) {
        initHandlerMappings(context);
        initHandlerAdapters();
        initViewResolvers();
        try {
            String[] namesArray = this.scanControllers();
            handlerMapping.initMapping(namesArray);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }


    protected void initHandlerMappings(ApplicationContext context) {
        try {
            this.handlerMapping = new RequestMappingHandlerMapping(context);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    protected void initHandlerAdapters() {
        try {
            this.handlerAdapter = new RequestMappingHandlerAdapterImpl();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    protected void initViewResolvers() {
        try {
            this.viewResolver = new InternalResourceViewResolver();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //super.service(req, resp);

        try {
            doDispatch(request, response);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
        }
    }

    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpServletRequest processedRequest = request;
        HandlerMethodInfo handlerMethod = null;
        ModelAndView mv = null;

        handlerMethod = this.handlerMapping.getHandler(processedRequest);


        //HandlerAdapter ha = this.handlerAdapter;

        HandlerAdapter handlerAdapterActual = this.handlerAdapter;

        mv = handlerAdapterActual.handle(processedRequest, response, handlerMethod);

        render(processedRequest, response, mv);




    }



    protected void render(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
        if (mv == null) {
            response.getWriter().flush();
            //response.getWriter().close();
            return;
        }

        String viewName = mv.getViewName();
        Map<String, Object> modelMap = mv.getModelMap();
        View view = createResolveViewName(viewName, modelMap, request);
        view.render(modelMap, request, response);

    }

    protected View createResolveViewName(String viewName, Map<String, Object> model,
                                         HttpServletRequest request) throws Exception {
        ViewResolver viewResolver = new InternalResourceViewResolver();
        if (viewResolver != null) {
            View view = viewResolver.resolveViewName(viewName);
            if (view != null) {
                return view;
            }
        }
        return null;
    }

    public String[] scanControllers() throws Exception {
        List<String> controllerNames = new ArrayList<>(256);
        ScanService scanService = new NormalScanService();
        Collection<String> objectDatas = scanService.scanPackages(SCAN_PACKAGE_NAME);
        for (String name : objectDatas) {
            Class<?> clazz = Class.forName(name);
            if (clazz.isAnnotationPresent(Controller.class)) {
                controllerNames.add(name);
            }
        }
        return controllerNames.toArray(new String[controllerNames.size()]);
    }

}
